﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Acms.Bll.Tests
{
    /// <summary>
    /// Summary description for EmailActivationCodeTests
    /// </summary>
    [TestClass]
    public class EmailActivationCodeTests : Base
    {
        public void ValidateList(List<TestData.EmailActivationCode> expected, List<Bll.EmailActivationCode> actual)
        {
            if (expected == null)
            {
                Assert.IsNull(actual);
            }
            else
            {
                Assert.IsNotNull(actual);
                foreach (var item in expected)
                {
                    ValidateProperties(item, actual[expected.IndexOf(item)]);
                }
            }
        }

        public void ValidateProperties(TestData.EmailActivationCode expected, Bll.EmailActivationCode actual)
        {
            if (expected == null)
            {
                Assert.IsNull(actual);
            }
            else
            {
                Assert.IsNotNull(actual);
                Assert.AreEqual(expected.Id, actual.Id);
                AssertHelper.AreEqual(expected.Activated.ToLocalTime(), actual.Activated);
                Assert.AreEqual(expected.Code, actual.Code);
                Assert.AreEqual(expected.Created.ToLocalTime(), actual.Created);
                Assert.AreEqual(expected.EmailAddress, actual.EmailAddress);
                Assert.AreEqual(expected.UserId, actual.UserId);
                AssertHelper.AreEqual(expected.ConcurencyId, (byte[])actual.ConcurencyId);
            }
        }

        private void ValidateProperties(Bll.EmailActivationCode expected, Bll.EmailActivationCode actual)
        {
            if (expected == null)
            {
                Assert.IsNull(actual);
            }
            else
            {
                Assert.IsNotNull(actual);
                Assert.AreEqual(expected.Id, actual.Id);
                AssertHelper.AreEqual(expected.Activated.ToLocalTime(), actual.Activated);
                Assert.AreEqual(expected.Code, actual.Code);
                Assert.AreEqual(expected.Created.ToLocalTime(), actual.Created);
                Assert.AreEqual(expected.EmailAddress, actual.EmailAddress);
                Assert.AreEqual(expected.UserId, actual.UserId);
                AssertHelper.AreEqual((byte[])expected.ConcurencyId, (byte[])actual.ConcurencyId);
            }
        }


        [TestMethod]
        public void EmailActivationCode_GetById_WithIncorrectId_ReturnsNull()
        {
            Assert.IsNull(Bll.EmailActivationCode.GetById(int.MaxValue));
        }

        [TestMethod]
        public void EmailActivationCode_GetById_WithCorrectId_ReturnsNotNull()
        {
            Assert.IsNotNull(Bll.EmailActivationCode.GetById(_TestEmailActivationCodes[0].Id));
        }

        [TestMethod]
        public void EmailActivationCode_GetById_WithCorrectId_PopulatesCorrectly()
        {
            var tmp = Bll.EmailActivationCode.GetById(_TestEmailActivationCodes[1].Id);
            ValidateProperties(_TestEmailActivationCodes[1], tmp);
        }

        [TestMethod]
        public void EmailActivationCode_GetAllByUserId_WithIncorrectId_ReturnsEmptyCount()
        {
            Assert.AreEqual(0, Bll.EmailActivationCode.GetAllByUserId(int.MaxValue).Count());
        }

        [TestMethod]
        public void EmailActivationCode_GetAllByUserId_WithCorrectId_ReturnsCorrectCount()
        {
            Assert.AreEqual(2, Bll.EmailActivationCode.GetAllByUserId(_TestUsers[0].Id).Count());
        }

        [TestMethod]
        public void EmailActivationCode_GetAllByUserId_WithCorrectId_PopulatesCorrectly()
        {
            var tmp = Bll.EmailActivationCode.GetAllByUserId(_TestUsers[0].Id);
            ValidateList(_TestEmailActivationCodes.Where(x => x.UserId == _TestUsers[0].Id).OrderByDescending(x => x.Created).ToList(), tmp);
        }

        [TestMethod]
        public void EmailActivationCode_Delete()
        {
            var tmp = Bll.EmailActivationCode.GetById(_TestEmailActivationCodes[0].Id);
            tmp.Delete();
            Assert.IsNull(Bll.EmailActivationCode.GetById(_TestEmailActivationCodes[0].Id));
            Assert.AreEqual(1, Bll.EmailActivationCode.GetAllByUserId(_TestUsers[0].Id).Count());
        }

        [TestMethod]
        [ExpectedExceptionAttribute(typeof(Exceptions.ConcurencyException))]
        public void EmailActivationCode_Delete_Concurency()
        {
            var tmp = Bll.EmailActivationCode.GetById(_TestEmailActivationCodes[0].Id);
            var tmp2 = Bll.EmailActivationCode.GetById(_TestEmailActivationCodes[0].Id);

            tmp2.SetAsActivated();
            try
            {
                tmp2.Update();
            }
            catch (Acms.Exceptions.ConcurencyException e)
            {
                throw new AssertFailedException("Concurency Exception not expected at this point", e);
            }
            
            tmp.Delete();
        }

        [TestMethod]
        public void EmailActivationCode_Update()
        {
            var expected = _Context.EmailActivationCodes.OrderBy(x => x.Id).First();
            var initalCID = expected.ConcurencyId;
            var tmp = Bll.EmailActivationCode.GetById(expected.Id);
            ValidateProperties(expected, tmp);

            tmp.SetAsActivated();
            tmp.Update();

            var tmp2 = Bll.EmailActivationCode.GetById(expected.Id);
            ValidateProperties(tmp2, tmp);
        }

        [TestMethod]
        public void EmailActivationCode_Insert()
        {
            var tmp = EmailActivationCode.CreateInstance(_TestUsers[0].Id, "activationTest@insert.com", _TestSites[0].Id);
            tmp.Update();

            ValidateProperties(_Context.EmailActivationCodes.Where(x => x.Id == tmp.Id).Single(), tmp);

            var tmp2 = Bll.EmailActivationCode.GetById(tmp.Id);

            ValidateProperties(tmp2, tmp);

        }

        [TestMethod]
        public void EmailActivationCode_ActivateEmailAddressWithIncorrectActivationCode_ReturnsCodeNotFound()
        {
            var user = Bll.User.GetById(_TestUsers.Where(x => !x.EmailAuthenticated).First().Id);
            Assert.IsNotNull(user);
            Assert.IsFalse(user.EmailAuthenticated);

            var tmp = user.ActivateEmailAddress("Rubbish", "Password 1");
            Assert.AreEqual(Bll.User.ActivateEmailAddressResult.Results.CodeNotFound, tmp.Status);

            Assert.IsFalse(user.EmailAuthenticated);
        }

        [TestMethod]
        public void EmailActivationCode_ActivateEmailAddressWithIncorrectPassword_ReturnsIncorrectPassword()
        {
            var dbUser = _TestUsers.Where(x => !x.EmailAuthenticated && x.EmailActivationCodes.Where(y => y.Activated == null).Count() > 0).First();
            var dbCode = dbUser.EmailActivationCodes.Where(x => x.Activated == null).First();

            var tmpUser = Bll.User.GetById(dbUser.Id);
            Assert.IsNotNull(tmpUser);
            Assert.IsFalse(tmpUser.EmailAuthenticated);

            var tmp = tmpUser.ActivateEmailAddress(dbCode.Code, "RubbishPassword 0");
            Assert.AreEqual(Bll.User.ActivateEmailAddressResult.Results.IncorrectPassword, tmp.Status);

            Assert.IsFalse(tmpUser.EmailAuthenticated);
        }

        [TestMethod]
        public void EmailActivationCode_ActivateEmailAddressWithCorrectDetails_ReturnsSuccess()
        {
            var dbUser = _TestUsers.Where(x => !x.EmailAuthenticated && x.EmailActivationCodes.Where(y => y.Activated == null).Count() > 0).First();
            var dbCode = dbUser.EmailActivationCodes.Where(x => x.Activated == null).First();

            int index = _TestUsers.IndexOf(dbUser);
            
            var tmpUser = Bll.User.GetById(dbUser.Id);

            Assert.IsNotNull(tmpUser);
            Assert.IsFalse(tmpUser.EmailAuthenticated);

            var tmp = tmpUser.ActivateEmailAddress(dbCode.Code, string.Format("Password{0}", index));
            Assert.AreEqual(Bll.User.ActivateEmailAddressResult.Results.Success, tmp.Status);

            Assert.IsTrue(tmpUser.EmailAuthenticated);
            Assert.AreEqual(dbCode.EmailAddress, tmpUser.EmailAddress);

            //check saved to db correctly
            var tmp2 = Bll.User.GetById(dbUser.Id);
            Assert.AreEqual(tmp2.EmailAuthenticated, tmpUser.EmailAuthenticated);
            Assert.AreEqual(tmp2.EmailAddress, tmpUser.EmailAddress);

            //check the avicatedproperty of emailactivationcode
            var tmpActivated = Bll.EmailActivationCode.GetById(dbCode.Id);
            Assert.IsNotNull(tmpActivated.Activated);
            Assert.IsTrue(DateTime.Now - tmpActivated.Activated.Value < TimeSpan.FromSeconds(1));
        }

        [TestMethod]
        public void EmailActivationCode_GetAllByUserIdAndEmail_WithInCorrectUserId_ReturnsEmptyList()
        {
            var tmp = Bll.EmailActivationCode.GetAllByUserIdAndEmail(int.MaxValue, _TestUsers[0].EmailAddress);
            Assert.AreEqual(0, tmp.Count);
        }

        [TestMethod]
        public void EmailActivationCode_GetAllByUserIdAndEmail_WithInCorrectEmail_ReturnsEmptyList()
        {
            var tmp = Bll.EmailActivationCode.GetAllByUserIdAndEmail(_TestUsers[0].Id, "Rubbish");
            Assert.AreEqual(0, tmp.Count);
        }

        [TestMethod]
        public void EmailActivationCode_GetAllByUserIdAndEmail_WithCorrectProperties_ReturnsCorrectList()
        {
            var tmp = Bll.EmailActivationCode.GetAllByUserIdAndEmail(_TestUsers[0].Id, _TestUsers[0].EmailActivationCodes[0].EmailAddress);
            var expected = _TestEmailActivationCodes.Where(x => x.Id == _TestUsers[0].Id && x.EmailAddress == _TestUsers[0].EmailActivationCodes[0].EmailAddress).ToList();
            ValidateList(expected, tmp);
        }

        [TestMethod]
        public void EmailActivationCode_GetByCodeAndSiteId_WithInCorrectCode_ReturnsNull()
        {
            var tmp = Bll.EmailActivationCode.GetByCodeAndSiteId("Rubbish", _TestEmailActivationCodes[0].User.SiteId.Value);
            Assert.IsNull(tmp);
        }

        [TestMethod]
        public void EmailActivationCode_GetByCodeAndSiteId_WithInCorrectSiteId_ReturnsEmptyList()
        {
            var tmp = Bll.EmailActivationCode.GetByCodeAndSiteId(_TestEmailActivationCodes[0].Code, int.MaxValue);
            Assert.IsNull(tmp);
        }

        [TestMethod]
        public void EmailActivationCode_GetByCodeAndSiteId_WithCorrectProperties_ReturnsCorrectList()
        {
            var tmp = Bll.EmailActivationCode.GetByCodeAndSiteId(_TestEmailActivationCodes[0].Code, _TestEmailActivationCodes[0].User.SiteId.Value);
            var expected = _TestEmailActivationCodes[0];
            ValidateProperties(expected, tmp);
        }
        /*[TestMethod]
        public void EmailActivationCode_GetByCode_WithValidCodeAndSiteId_ReturnsNotNull()
        {
            EmailActivationCodeFactory factory = new EmailActivationCodeFactory(_Context);
            Assert.IsNotNull(Bll.EmailActivationCode.GetByCode(_TestEmailActivationCodes[1].Code, _TestSite.Id));
        }

        [TestMethod]
        public void EmailActivationCode_GetByCode_WithInvalidCode_ReturnsNull()
        {
            EmailActivationCodeFactory factory = new EmailActivationCodeFactory(_Context);
            Assert.IsNull(Bll.EmailActivationCode.GetByCode("rubbish", _TestSite.Id));
        }

        [TestMethod]
        public void EmailActivationCode_GetByCode_WithInvalidSiteId_ReturnsNull()
        {
            EmailActivationCodeFactory factory = new EmailActivationCodeFactory(_Context);
            Assert.IsNull(Bll.EmailActivationCode.GetByCode(_TestEmailActivationCodes[1].Code, _AlternateSite.Id));
        }*/
    }
}
